package com.reservation.service.impl;

import com.reservation.dto.user.booking.ConfirmReservationDTO;
import com.reservation.dto.user.booking.PayDTO;
import com.reservation.dto.user.booking.RoomFilterDTO;
import com.reservation.entity.Bookings;
import com.reservation.entity.MeetingRooms;
import com.reservation.enumeration.BookingStatus;
import com.reservation.exception.BaseException;
import com.reservation.mapper.BookingMapper;
import com.reservation.mapper.OrderMapper;
import com.reservation.service.BookingService;
import com.reservation.utils.CurrentHolderUtil;
import com.reservation.vo.user.AvailableRoomVO;
import com.reservation.vo.user.ConfirmReservationVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;

@Service
@Slf4j
public class BookingServiceImpl implements BookingService {

    @Autowired
    private BookingMapper bookingMapper;
    
    @Autowired
    private OrderMapper orderMapper;

    /**
     * 解析日期时间字符串并组合成LocalDateTime对象
     *
     * @param dateStr      日期字符串，格式为ISO_LOCAL_DATE
     * @param startTimeStr 开始时间字符串，格式为"HH-mm"
     * @param endTimeStr   结束时间字符串，格式为"HH-mm"
     * @return 包含开始和结束时间的LocalDateTime对象数组
     */
    private LocalDateTime[] parseDateTime(String dateStr, String startTimeStr, String endTimeStr) {
        // 解析日期
        LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE);

        // 解析时间格式 (09:00)
        String[] startParts = startTimeStr.split(":");
        String[] endParts = endTimeStr.split(":");

        LocalTime startTime = LocalTime.of(Integer.parseInt(startParts[0]), Integer.parseInt(startParts[1]));
        LocalTime endTime = LocalTime.of(Integer.parseInt(endParts[0]), Integer.parseInt(endParts[1]));

        // 组合成完整的日期时间
        LocalDateTime startDateTime = LocalDateTime.of(date, startTime);
        LocalDateTime endDateTime = LocalDateTime.of(date, endTime);

        return new LocalDateTime[]{startDateTime, endDateTime};
    }

    /**
     * 生成10位随机订单号
     */
    private String generateRandomOrderId() {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10; i++) {
            sb.append(random.nextInt(10));
        }
        return sb.toString();
    }

    // 解析设备字符串为列表
    private List<String> parseEquipmentString(String equipmentJson) {
        // 假设存储格式是JSON数组字符串 ["投影仪","音响系统","无线网络"]
        // 这里简单处理，实际可能需要使用JSON库
        String processed = equipmentJson.replace("[", "")
                .replace("]", "")
                .replace("\"", "");

        return Arrays.asList(processed.split(","));
    }


    /**
     * 筛选可用会议室
     *
     * @param filterDTO 过滤条件
     * @return 可用会议室列表
     */
    @Override
    public List<AvailableRoomVO> filterAvailableRooms(RoomFilterDTO filterDTO) {
        // 解析日期和时间
        LocalDateTime[] dateTimes = parseDateTime(filterDTO.getDate(), filterDTO.getStartTime(), filterDTO.getEndTime());
        LocalDateTime startDateTime = dateTimes[0];
        LocalDateTime endDateTime = dateTimes[1];

        // 获取LocalTime，用于后续比较
        LocalTime startTime = startDateTime.toLocalTime();
        LocalTime endTime = endDateTime.toLocalTime();

        // 需要的参会人数
        int requiredCapacity = filterDTO.getNumber();
        // 需要的设备列表
        List<String> requiredEquipment = filterDTO.getEquipment();

        // 1. 查询指定日期所有未预约满的会议室
        LocalDate bookingDate = startDateTime.toLocalDate();
        List<MeetingRooms> allAvailableRooms = bookingMapper.findAvailableRooms(bookingDate);

        // 2. 筛选出符合条件的会议室
        List<AvailableRoomVO> result = new ArrayList<>();

        for (MeetingRooms room : allAvailableRooms) {
            // 检查容量是否满足
            if (room.getCapacity() < requiredCapacity) {
                continue;
            }

            // 检查会议室当天的可用时间是否覆盖请求的时间段
            if (startTime.isBefore(room.getAvailableStartTime()) ||
                    endTime.isAfter(room.getAvailableEndTime())) {
                continue;
            }

            // 检查设备是否满足
            if (requiredEquipment != null && !requiredEquipment.isEmpty()) {
                // 解析会议室的设备列表 (假设是JSON字符串)
                List<String> roomEquipment = parseEquipmentString(room.getEquipmentDetails());

                // 检查是否包含所有需要的设备
                if (!new HashSet<>(roomEquipment).containsAll(requiredEquipment)) {
                    continue;
                }
            }

            // 检查该时间段是否已被预订
            boolean isBooked = bookingMapper.isRoomBooked(room.getId(), startDateTime, endDateTime);
            if (isBooked) {
                continue;
            }



            // 转换为VO对象
             AvailableRoomVO vo =AvailableRoomVO.builder()
                    .id(room.getId())
                    .name(room.getName())
                    .type(room.getType())
                    .number(room.getCapacity())
                    .area(room.getAreaSqm())
                    .equipment(parseEquipmentString(room.getEquipmentDetails()))
                    .price(room.getPricePerHour())
                    .build();

            result.add(vo);
        }

        return result;
    }

    /**
     * 预订会议室
     *
     * @param dto 预订信息
     * @return 预订结果
     */
    @Override
    @Transactional
    public ConfirmReservationVO confirmReservation(ConfirmReservationDTO dto) {
        // 1. 获取当前用户ID
        Integer currentUserId = CurrentHolderUtil.getCurrentId();
        if (currentUserId == null) {
            throw new BaseException("用户未登录或登录已过期");
        }

        // 2. 解析日期和时间
        LocalDateTime[] dateTimes = parseDateTime(dto.getDate(), dto.getStartTime(), dto.getEndTime());
        LocalDateTime startDateTime = dateTimes[0];
        LocalDateTime endDateTime = dateTimes[1];
        LocalTime startTime = startDateTime.toLocalTime();
        LocalTime endTime = endDateTime.toLocalTime();

        // 3. 检查会议室是否可用（当前时间段内没有被预订）
        if (bookingMapper.isRoomBooked(dto.getId(), startDateTime, endDateTime)) {
            throw new BaseException("所选时段该会议室已被预订，请选择其他时段或其他会议室");
        }

        // 4. 计算会议时长和总价
        BigDecimal pricePerHour = bookingMapper.getRoomPricePerHour(dto.getId());
        double hoursDuration = (double) ChronoUnit.MINUTES.between(startTime, endTime) / 60;
        BigDecimal durationHours = BigDecimal.valueOf(hoursDuration);
        BigDecimal totalPrice = pricePerHour.multiply(durationHours);

        // 5. 随机生成订单号 (#1234567890 格式)
        String orderIdString = "#" + generateRandomOrderId();

        // 6. 设置支付截止时间（当前时间+30分钟）
        LocalDateTime paymentDeadline = LocalDateTime.now().plusMinutes(30);

        // 7. 创建预订记录
        Bookings booking = Bookings.builder()
                .customerId(currentUserId.longValue())
                .roomId(dto.getId())
                .orderId(orderIdString)
                .startTime(startDateTime)
                .endTime(endDateTime)
                .durationHours(durationHours)
                .totalPrice(totalPrice)
                .status(BookingStatus.PENDING_PAYMENT.getCode()) // 设置为待支付状态
                .paymentDeadline(paymentDeadline)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();

        // 8. 保存预订记录并获取生成的ID
        int result = bookingMapper.insertBooking(booking);
        if (result <= 0) {
            throw new BaseException("创建预约失败，请重试");
        }

        // 9. 返回预约结果
        return ConfirmReservationVO.builder()
                .id(booking.getId())
                .orderID(orderIdString)
                .total(totalPrice)
                .build();
    }

    /**
     * 支付订单
     *
     * @param payDTO 支付信息
     */
    @Override
    @Transactional
    public void pay(PayDTO payDTO) {

        // 检查订单是否存在
        Bookings booking = bookingMapper.getBookingByOrderId(payDTO.getId());
        if (booking == null) {
            throw new BaseException("订单不存在或已被取消");
        }

        // 检查支付状态
        if (BookingStatus.CONFIRMED.getCode().equals(booking.getStatus())) {
            throw new BaseException("订单已支付，请勿重复支付");
        }
        
        // 获取订单总金额和用户ID
        Double totalAmount = booking.getTotalPrice().doubleValue();
        Long userId = booking.getCustomerId();
        
        // 从用户钱包中扣款
        int walletResult = orderMapper.updateUserWalletDecrease(userId, totalAmount, payDTO.getPayMethod());
        if (walletResult <= 0) {
            throw new BaseException("支付失败，请确认钱包余额充足");
        }

        // 更新订单状态为已支付
        booking.setStatus(BookingStatus.CONFIRMED.getCode());
        booking.setPaidAt(LocalDateTime.now());
        booking.setUpdateTime(LocalDateTime.now());
        booking.setPaidMethod((int) payDTO.getPayMethod());
        int result = bookingMapper.updateBooking(booking);
        if (result <= 0) {
            throw new BaseException("支付失败，请重试");
        }

    }
}